# -*- coding: utf-8 -*-

from .token import Token, TokenType

EOF = '\x00'


def is_digit(ch):
    return '0' <= ch <= '9'


def is_symbol(ch):
    allow_chs = '+-*/=<>'
    return ('a' <= ch <= 'z') or ('A' <= ch <= 'Z') or ch in allow_chs


class Lexer:
    def __init__(self, input):
        self.input = input
        self.position = 0
        self.read_position = 0
        self.ch = None
        self.read_char()

    def next_token(self):
        tok = None
        self.skip_whitespace()
        ch = self.ch
        if ch == '(':
            tok = Token(TokenType.LPAREN, ch)
        elif ch == ')':
            tok = Token(TokenType.RPAREN, ch)
        elif ch == '"':
            tok = Token(TokenType.STRING, self.read_string())
        elif ch == EOF:
            tok = Token(TokenType.EOF, '')
        else:
            if is_symbol(ch):
                return Token(TokenType.SYMBOL, self.read_symbol())
            elif is_digit(ch):
                return Token(TokenType.NUMBER, self.read_number())
            else:
                tok = Token(TokenType.ILLEGAL, ch)

        self.read_char()
        return tok

    def skip_whitespace(self):
        while self.ch in [' ', '\t', '\n', '\r']:
            self.read_char()

    def read_char(self):
        if self.read_position >= len(self.input):
            self.ch = EOF
        else:
            self.ch = self.input[self.read_position]

        self.position = self.read_position
        self.read_position += 1

    def peek_char(self):
        if self.read_position >= len(self.input):
            return EOF
        else:
            return self.input[self.read_position]

    def read_string(self):
        start_pos = self.position + 1
        while True:
            self.read_char()
            if self.ch == '"' or self.ch == EOF:
                break
        return self.input[start_pos:self.position]

    def read_number(self):
        start_pos = self.position
        while is_digit(self.ch):
            self.read_char()
        return self.input[start_pos:self.position]

    def read_symbol(self):
        start_pos = self.position
        while is_symbol(self.ch):
            self.read_char()
        return self.input[start_pos:self.position]
